﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Micro.AspNetCore.ApiWidgets
{

    public class ApiResult : IApiResult
    {
        private static readonly DateTime UnitTime = DateTime.Parse("1970-01-01 00:00:00");
        /// <summary>
        /// Represents an empty <see cref="IApiResult"/>.
        /// </summary>
        public static readonly IApiResult Empty = new ApiResult
        {
            StatusCode = 204
        };

        /// <summary>
        /// Gets or sets the status code.
        /// </summary>
        /// <value>The status code.</value>
        public int StatusCode { get; set; }

        /// <summary>
        /// Gets or sets the message.
        /// </summary>
        /// <value>The message.</value>
        public string Message { get; set; }

        /// <summary>
        /// 时间戳
        /// </summary>
        public double Timestamp { get; set; }


        public bool IsSuccess { get; set; }
        public int Code { get; set; }
        public int DataCount { get; set; }

        public object Data { get; set; }

        public T GetData<T>()
        {
            if (Data != null)
            {
                if (Data is T)
                    return (T)Data;
                else if (Data.ToString().NotNull())
                {
                    T t = JsonConvert.DeserializeObject<T>(Data.ToString());
                    return t;
                }
            }
            return default;
        }

        public static double GetTimestamp()
        {
            return (DateTime.Now - UnitTime).TotalMilliseconds;
        }

        /// <summary>
        /// Creates a new instance of <see cref="IApiResult{TResult}"/> by the specified result.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="result">The result.</param>
        /// <returns>An instance inherited from <see cref="IApiResult{TResult}"/> interface.</returns>
        public static IApiResult<TResult> Succeed<TResult>(TResult result, int dataCount = 0, string message = null) => new ApiResult<TResult>
        {
            StatusCode = 200,
            Code = 0,
            Data = result,
            DataCount = dataCount,
            Message = message,
            IsSuccess = true,
            Timestamp = GetTimestamp()
        };


        public static async Task<IApiResult<TResult>> SucceedAsync<TResult>(TResult result, int dataCount = 0, string message = null) => await Task.FromResult(Succeed(result, dataCount, message));

        /// <summary>
        ///  Creates a new instance of <see cref="IApiResult"/> by the specified error message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="statusCode">The status code</param>
        /// <returns>An instance inherited from <see cref="IApiResult"/> interface.</returns>
        public static IApiResult Failed(string message, int? statusCode = null) => new ApiResult
        {
            IsSuccess = false,
            Code = -100,
            StatusCode = statusCode ?? 400,
            Message = message,
            DataCount = 0
        };

        public static async Task<IApiResult> FailedAsync(string message, int? statusCode = null) => await Task.FromResult(Failed(message, statusCode));



        /// <summary>
        ///  Creates a new instance of <see cref="IApiResult{TResult}"/> by the specified error message.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="errorResult">The error result.</param>
        /// <param name="message">The message.</param>
        /// <param name="statusCode">The status code.</param>
        /// <returns>An instance inherited from <see cref="IApiResult"/> interface.</returns>
        public static IApiResult<TResult> Failed<TResult>(TResult errorResult, string message, int? statusCode = null) => new ApiResult<TResult>
        (errorResult, code: -100, statusCode: 400, dataCount: 0, message: message);

        public static async Task<IApiResult<TResult>> FailedAsync<TResult>(TResult errorResult, string message, int? statusCode = null) => await Task.FromResult(Failed(errorResult, message, statusCode));

        public static IApiResult Error(string message, int? code = -600) => new ApiResult
        {
            IsSuccess = false,
            Code = code ?? -600,
            StatusCode = 500,
            Message = message,
            DataCount = 0,
        };


        /// <summary>
        /// Creates a new instance of <see cref="IApiResult"/> by the specified status code and message.
        /// </summary>
        /// <param name="statusCode">The status code.</param>
        /// <param name="message">The message.</param>
        /// <returns>An instance inherited from <see cref="IApiResult"/> interface.</returns>
        public static IApiResult From(int code, string message = null, int statusCode=200) => new ApiResult
        {
            Code = code,
            IsSuccess = code == 0,
            StatusCode = statusCode,
            Message = message
        };

        /// <summary>
        /// Creates a new instance of <see cref="IApiResult{TResult}"/> by the specified result.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="result">The result.</param>
        /// <param name="statusCode">The status code.</param>
        /// <param name="message">The message.</param>
        /// <returns>An instance inherited from <see cref="IApiResult{TResult}"/> interface.</returns>
        public static IApiResult<TResult> From<TResult>(TResult result, int code, string message, int statusCode = 200) => new ApiResult<TResult>
        {
            Code = code,
            IsSuccess = code == 0,
            StatusCode = statusCode,
            Message = message,
            Data = result
        };


        public static IApiResult<TResult> From<TResult>(TResult result, int code, string message, int dataCount = 0, int statusCode = 200) => new ApiResult<TResult>
        {
            Code = code,
            IsSuccess = code == 0,
            StatusCode = statusCode,
            Message = message,
            DataCount = dataCount,
            Data = result
        };
    }
}
